{
 "cells": [
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "d8ed1d4e",
   "metadata": {},
   "source": [
    "# 数组广播机制\n",
    "\n",
    "数组支持广播机制，支持对一些形状不同但满足一定条件的多个数组进行一些二元操作："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "8001e616",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "276f685f",
   "metadata": {},
   "source": [
    "数组形状相同的情况："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "ce6c7bba",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([1.0, 2.0, 3.0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "b441ffd6",
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.array([2.0, 2.0, 2.0])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "5b4f5d52",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3,)"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "bfff2c17",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3,)"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.shape"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "d7a843fb",
   "metadata": {},
   "source": [
    "也有两个不同维度操作的例子，如数组的数乘："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "e828ac3a",
   "metadata": {},
   "outputs": [],
   "source": [
    "c = 2.0"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "id": "98e015d3",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([2., 4., 6.])"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a * c"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "0bff1593",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "()"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "np.shape(c)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b98958ae",
   "metadata": {},
   "source": [
    "再看一个更复杂的例子："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "49fe66e3",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([\n",
    "    [0, 0, 0],\n",
    "    [10, 10, 10],\n",
    "    [20, 20, 20],\n",
    "    [30, 30, 30],\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "2b9682dd",
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.array([\n",
    "    [0, 1, 2],\n",
    "    [0, 1, 2],\n",
    "    [0, 1, 2],\n",
    "    [0, 1, 2],\n",
    "])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "e87ad5aa",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2],\n",
       "       [10, 11, 12],\n",
       "       [20, 21, 22],\n",
       "       [30, 31, 32]])"
      ]
     },
     "execution_count": 11,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a + b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ebcce5c9",
   "metadata": {},
   "source": [
    "将`b`的形状改为(3,)的一维数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 12,
   "id": "bdac669c",
   "metadata": {},
   "outputs": [],
   "source": [
    "b = np.array([0, 1, 2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 13,
   "id": "49680b08",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3,)"
      ]
     },
     "execution_count": 13,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.shape"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 14,
   "id": "3daf1c6e",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(4, 3)"
      ]
     },
     "execution_count": 14,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8626e64e",
   "metadata": {},
   "source": [
    "此时，加法仍然成立："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 15,
   "id": "8d34f0dd",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2],\n",
       "       [10, 11, 12],\n",
       "       [20, 21, 22],\n",
       "       [30, 31, 32]])"
      ]
     },
     "execution_count": 15,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a + b"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7999bee4",
   "metadata": {},
   "source": [
    "再将a的形状修改为一个(4,1)的数组："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 16,
   "id": "c9e2fa4d",
   "metadata": {},
   "outputs": [],
   "source": [
    "a = np.array([0, 10, 20, 30])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 17,
   "id": "f3104b3f",
   "metadata": {},
   "outputs": [],
   "source": [
    "a.shape = 4, 1"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "850a8492",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0],\n",
       "       [10],\n",
       "       [20],\n",
       "       [30]])"
      ]
     },
     "execution_count": 18,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "32de526b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(3,)"
      ]
     },
     "execution_count": 19,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "b.shape"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "34f6f8a5",
   "metadata": {},
   "source": [
    "此时，加法依然成立："
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 20,
   "id": "be975f8f",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "array([[ 0,  1,  2],\n",
       "       [10, 11, 12],\n",
       "       [20, 21, 22],\n",
       "       [30, 31, 32]])"
      ]
     },
     "execution_count": 20,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "a + b"
   ]
  },
  {
   "attachments": {},
   "cell_type": "markdown",
   "id": "99963ae4",
   "metadata": {},
   "source": [
    "在上面的例子中，两个数组的形状虽然不一样，但是加法操作仍然适用。这是由于NumPy数组存在广播机制（Broadcasting）导致的。\n",
    "\n",
    "在广播机制下，当两个数组进行二元操作时，NumPy会对它们的形状进行检查，如果两个数组形状匹配，NumPy会按照一定的规则将它们变成两个形状相同的数组，再进行相应的二元操作。\n",
    "\n",
    "在广播机制中，两个数组的匹配规则如下：\n",
    "- 规则1：两个数组的形状完全一致。\n",
    "- 规则2：两个数组的维度一样，对应的维度大小相同，或者其中一个大小为1。\n",
    "- 规则3：两个数组的维度个数不同时，在低维数组前增加大小为1的维度直到与高维数组维度相等，然后应用前两个规则判断。\n",
    "\n",
    "匹配成功后，结果数组每个维度的大小取两个数组对应维度大小较大的一个。利用广播机制，不难解释上面例子中的运算过程：\n",
    "\n",
    "形状相同的加法：\n",
    "```\n",
    "a：4×3\n",
    "b：4×3\n",
    "```\n",
    "规则1适用。\n",
    "\n",
    "只改b的加法：\n",
    "```\n",
    "a：4×3\n",
    "b：  3\n",
    "```\n",
    "先根据规则3，将b扩展成(1,3)，再根据规则2匹配成功。\n",
    "\n",
    "再改a的加法：\n",
    "```\n",
    "a：4×1\n",
    "b：  3\n",
    "```\n",
    "先根据规则3，将b扩展成(1,3)，再根据规则2匹配成功。\n",
    "\n",
    "更复杂的例子：\n",
    "```\n",
    "a   ：3d array - 256 x 256 x 3\t\n",
    "b   ：1d array -             3\n",
    "res ：3d array - 256 x 256 x 3\n",
    "```\n",
    "\n",
    "```\n",
    "a   ：4d array - 8 x 1 x 6 x 1\n",
    "b   ：3d array -     7 x 1 x 5\n",
    "res ：3d array - 8 x 7 x 6 x 5\n",
    "```\n",
    "\n",
    "```\n",
    "a   ：2d array - 4 x 1\t\n",
    "b   ：1d array -     3\n",
    "res ：2d array - 4 x 3\n",
    "```"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "74a2318e",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "language": "python",
   "name": "python3"
  },
  "language_info": {
   "codemirror_mode": {
    "name": "ipython",
    "version": 3
   },
   "file_extension": ".py",
   "mimetype": "text/x-python",
   "name": "python",
   "nbconvert_exporter": "python",
   "pygments_lexer": "ipython3",
   "version": "3.9.10"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
